package cn.rokhdelar.ams.config.aspect;

import cn.rokhdelar.ams.config.cache.Debounce;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author shenyongqiang
 * @since 2025-04-25  12:31
 */
@Aspect
@Component
public class DebounceAspect {
    private final CacheManager cacheManager;

    @Autowired
    public DebounceAspect(@Qualifier("cacheConfigForCachePackage") CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Around("@annotation(cn.rokhdelar.ams.config.cache.Debounce) && execution(* cn.rokhdelar.ams.business..controller.*.*(..))")
    public Object debounce(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            Debounce debounce = method.getAnnotation(Debounce.class);
            int debounceTime = debounce.value();
            String cacheName = debounce.cacheName();

            String requestKey = generateRequestKey(joinPoint);
            Cache cache = cacheManager.getCache(cacheName);

            if (cache.get(requestKey)!= null) {
                return ResponseEntity.ok("请勿频繁请求");
            }

            cache.put(requestKey, "processed");
            new java.util.Timer().schedule(
                    new java.util.TimerTask() {
                        @Override
                        public void run() {
                            cache.evict(requestKey);
                        }
                    },
                    TimeUnit.SECONDS.toMillis(debounceTime)
            );

            return joinPoint.proceed();
        } catch (Exception e) {
            throw e;
        }
    }

    private String generateRequestKey(ProceedingJoinPoint joinPoint) {
        StringBuilder key = new StringBuilder();
        key.append(joinPoint.getTarget().getClass().getName());
        key.append(".");
        key.append(joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg!= null) {
                key.append(arg.toString());
            }
        }
        return key.toString();
    }
}